#ifndef _DynamicColorScaleStructs_h__
#define _DynamicColorScaleStructs_h__

#include <buildspec.h>
#include <GSTenums.h>
#include <Utils/Color.h>
#include <Client/ClientUtils/Network/TableAttributeVal.h>
#include <Client/ClientUtils/Network/ObjectPropertyDesc.h>

#include <boost/shared_ptr.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>

#include <vector>
#include <string>
#include <set>

namespace GST {
namespace ClientUtils {

	//prototypes
	class DynamicColorValue;
	typedef boost::shared_ptr<DynamicColorValue> DynamicColorValuePtr;
	class DynamicColorScale;

class GST_API_EXPORT DynamicColorValue
{
	friend class DynamicColorScale;

public:	
	typedef long ID;

	DynamicColorValue();

	/**
	  * @returns true if this is a DCVNoData
	  */
	virtual bool isNoDataValue() const;

	///@name getter / setter 
	//@{
	GST::ClientUtils::DynamicColorValue::ID getId() const { return m_id; }
	void setId(GST::ClientUtils::DynamicColorValue::ID val) { m_id = val; }
	std::string getLabel() const { return m_label; }
	void setLabel(std::string val) { m_label = val; }
	Utils::ColorRGBA getColor() const { return m_color; }
	void setColor(Utils::ColorRGBA val) { m_color = val; }
	static ID GetNewId();
	const DynamicColorScale * getScale() const;
	//@}

protected:
	ID m_id;	
	std::string m_label;	
	Utils::ColorRGBA m_color;	
	DynamicColorScale * m_parent;
	static const ID NewId;
}; 
typedef std::vector<DynamicColorValuePtr> DynamicColorValueList;
typedef boost::shared_ptr<DynamicColorValueList> DynamicColorValueListPtr;

//------------------------------------------------------------------------------

class GST_API_EXPORT	DCVInterval
	: public DynamicColorValue
{
public:
	virtual bool isNoDataValue() const;

	///@name getter / setter 
	//@{
	double getToValue() const { return m_toValue; }
	void setToValue(double val) { m_toValue = val; }
	//@}

	bool compare(const DCVInterval & other) const;

protected:
	double m_toValue;	  	
};
typedef boost::shared_ptr<DCVInterval> DCVIntervalPtr;
typedef std::vector<DCVIntervalPtr> DCVIntervalList;
typedef boost::shared_ptr<DCVIntervalList> DCVIntervalListPtr;

//--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --

struct GST_API_EXPORT IntervalCompare
{
	bool operator() (const DCVIntervalPtr & lhs
		, const DCVIntervalPtr & rhs) const;
};
typedef std::set<DCVIntervalPtr, IntervalCompare> DCVIntervalSet;
typedef boost::shared_ptr<DCVIntervalSet> DCVIntervalSetPtr;

//------------------------------------------------------------------------------

class GST_API_EXPORT DCVQuantum
	: public DynamicColorValue
{
public:

	DCVQuantum();

	virtual bool compare(const DynamicColorValuePtr & other) const;
	virtual bool isNoDataValue() const;

	//helper to find this in set
	static bool CompareValue(DynamicColorValuePtr comparer, const std::string & value);

	///@name getter / setter 
	//@{
	std::string getValue() const { return m_value; }
	void setValue(std::string val) { m_value = val; }
	int getOrder() const { return m_order; }
	void setOrder(int val) { m_order = val; }
	//@}	

	template<typename T>
	T getAs() const;

protected:
	std::string m_value;
	int m_order; 
};
typedef boost::shared_ptr<DCVQuantum> DCVQuantumPtr; 
typedef std::vector<DCVQuantumPtr> DCVQuantumList;
typedef boost::shared_ptr<DCVQuantumList> DCVQuantumListPtr;

template<typename T>
T DCVQuantum::getAs() const
{
	return boost::lexical_cast<T>(this->m_value);
}

//------------------------------------------------------------------------------

/**
  * Dynamic Color Scale base class.
  * 
  * Dynamic color scales are used to give TabeAttributeVal a color+label.
  * Similar to ColorScale and ColorValue structs of MoMa this are classes
  * to interpret features but here by value (not static).
  *
  * DynamicColorScale's constructed by default constructor are new ColorScales
  * (m_id == NewId). Retreive DynamicColorScales through the NetworkInterface
  * or create your own one, by inserting DCVQuantum or DCVInterval.
  *
  * <li> DCVQuantum are used for discrete value interpretation 
  *      (DynamicDiscreteScale) </li>
  * <li> DCVInterval are used for continuous value interpretations 
  *      (DynamicContinousScale)
  *
  * To connect DynamicColorScales to feature or feature classes the member 
  * m_regex is used to match FeatureClass attributes by name. A "regex" is 
  * a semicolon separated list of Property names (including the wildcards 
  * '*' - Kleene star and '?' - any char).
  * Use the Match*() methods to validate if DynamicColorScales is applicable
  * to a feature.
  */
class GST_API_EXPORT DynamicColorScale
{
public:
	typedef long ID;
	typedef enum DynamicCSType { TypeContinuous, TypeDiscrete } DynamicCSType;

	static std::string TypeToString(DynamicCSType type);
	static DynamicCSType StringToType(const std::string & type);

	DynamicColorScale();
	DynamicColorScale(const DynamicColorScale & other);
	DynamicColorScale& operator=(const DynamicColorScale& rhs);
	virtual DynamicColorScale * clone() = 0;

	/**	@returns a human readable string to identify the color scale */
	std::string ToIdentityString() const;

	///@name getter / setter 
	//@{
	GST::ClientUtils::DynamicColorScale::ID getId() const { return m_id; }
	void setId(GST::ClientUtils::DynamicColorScale::ID val) { m_id = val; }
	std::string getLabel() const { return m_label; }
	void setLabel(std::string val) { m_label = val; }
	Utils::ColorRGBA getNdvColor() const;
	void setNdvColor(Utils::ColorRGBA val);
	std::string getNdvLabel() const;
	void setNdvLabel(std::string val);
	std::string getRegEx() const;
	void setRegEx(std::string val);
	static ID GetNewId();
	bool isNdvDominant() const { return m_ndvDominantes; }
	void setNdvDominantes(bool val) { m_ndvDominantes = val; }
	long getAccessLevelId() const { return m_accessLevelId; }
	void setAccessLevelId(long accessLevelId) { m_accessLevelId = accessLevelId; }
	//@}

	/**
	  * @return the color scale type
	  */
	virtual DynamicCSType getType() const = 0;

	/**
	  * @returns the number of classes
	  */
	virtual int size() const = 0;
	/**
	  * @return true if the class has no color values
	  */
	virtual bool empty() const;

	/**
	  * Removes all color value from scale. (Afterwards empty() will return true)
	  */
	virtual void clear() = 0;

	///@name iteration interface (ordered ascendant)
	//@{
	/**
	  * Set the intern iterator to end. (next incrIterator will move to first
	  * color value)
	  */
	virtual void resetIterator() = 0;

	/**
	  * Increment intern iterator. @returns false if this is not possible (end of
	  * container).
	  */
	virtual bool incrIterator() = 0;

	/**
	  * @returns element at iterators position
	  *
	  * @throw GSTRuntimeException if iterator points to the end (avoid this
	  *        by checking incrIterator() that returns false)
	  */
	virtual DynamicColorValuePtr getIteratorRef() const = 0;
	//@}

	///@name DynamicColorValue getter/setter interface
	//@{
	/**
	  * Appends a ColorValue to the color scale.
	  *
	  * @note Take care to insert the color value type to the scale DCVQuantum 
	  *       or DCVNoData to a DynamicDiscreteScale and DCVInterval or 
	  *       DCVNoData to a DynamicContinousScale.
	  *
	  * @throws exceptions::GSTRuntimeException Adding a wrong type will throw.
	  */
	virtual void insert(DynamicColorValuePtr dcv) = 0;

	/**
	  * Tries to drop the value dcv from scale.
	  *
	  * In case dcv is not a value of this scale or being the null data value
	  * an ouput to debug console will be send.
	  * @see Utils::Console::SendDebug()
	  */
	virtual void drop(const DynamicColorValue & dcv) = 0;
	virtual void drop(DynamicColorValuePtr dcv);

	/**
	  * General getter. Depending in this Color Scale type
	  * <ul>
	  * <li> Return interval color value (DCVInterval) for the given value
	  *      or DCVNoDataPtr if value is greater as the biggest inserted 
	  *      DCVInterval or smaller/equal the smallest inserted DCVInterval</li>
	  * <li> Return discrete color value (DCVQuantum) for the given value
	  *      or DCVNoDataPtr if value is not inserted before.</li>
	  * </ul>
	  */
	virtual DynamicColorValuePtr GetColorValue(const TableAttributeVal & tval) const = 0;

	virtual DynamicColorValuePtr GetColorValue(const std::string & objectValue) const;
	/**
	  * Returns the no data color value
	  */
	virtual DynamicColorValuePtr GetNoDataColorValue() const;
	//@}

	///@name Match methods
	//@{
	/**
	  * Returns true if desc is matched by the colorscales regex. A "regex" is
	  * a semicolon separated list of Property names (including the wildcards
	  * '*' - Kleene star and '?' - any char).
	  */
	bool MatchByName(const std::string & attributeName) const;

	/**
	 * Return true for compatible dtype. For Descrete Scale the
	 * TableAttributeVal::ToString() resp for Continous Scale the
	 * TableAttributeVal::ToDouble() is called on
	 * DynamicColorScale::GetColorValue(). This methods returns true if the
	 * DType is castable to the scale getter.
	 */
	bool MatchByDType(const TableAttributeDesc::DType & desc) const;

	/**
	 * @returns true if MatchByName() and MatchByDType() matches for the
	 * TableAttributeDesc
	 */
	bool Match(const TableAttributeDesc & desc) const;

	/**
	  * Match by ObjectPropertyDescList (each by name). A ObjectPropertyDescList
	  * is renturned by NetworkInterface::GetObjectPropertyList().
	  * 
	  * @returns the first matching property or return an empty pointer if no 
	  * ObjectPropertyDesc is matched.
	  */
	ObjectPropertyDescPtr GetMatched(const ObjectPropertyDescList & list) const;

	/**
	 * Use this to detect multiple matches.
	 * @returns All ObjectPropertyDesc from list that are matching the regEx. 
	 */
	ObjectPropertyDescList GetMatchedAll(const ObjectPropertyDescList & list) const;
	//@}

protected:
	ID m_id;	
	std::string m_label;	
	DynamicColorValuePtr m_ndvValue;
	std::vector<std::string> m_attributeMatches;
	static const ID NewId;
	long m_accessLevelId;
	bool m_ndvDominantes;
	void setThisAsParent(DynamicColorValue * value);
};
typedef boost::shared_ptr<DynamicColorScale> DynamicColorScalePtr; 
typedef std::vector<DynamicColorScalePtr> DynamicColorScaleList;
typedef boost::shared_ptr<DynamicColorScaleList> DynamicColorScaleListPtr;

//------------------------------------------------------------------------------

class GST_API_EXPORT DynamicContinousScale
	: public DynamicColorScale
{
public:

	DynamicContinousScale();
	DynamicContinousScale(const DynamicContinousScale & other);
	DynamicContinousScale& operator=(const DynamicContinousScale& rhs);
	virtual DynamicColorScale * clone();

	virtual int size() const;
	virtual void clear();
	virtual DynamicColorScale::DynamicCSType getType() const;

	///@name DynamicColorValue getter/setter interface
	//@{
	virtual DynamicColorValuePtr GetColorValue(
		const TableAttributeVal & tval) const;
	virtual DynamicColorValuePtr GetColorValue(const std::string & objectValue) const;
	virtual void insert(DynamicColorValuePtr dcv);
	virtual void drop(const DynamicColorValue & dcv);
	//@}

	///@name iteration interface
	//@{
	virtual void resetIterator();
	virtual bool incrIterator();
	virtual DynamicColorValuePtr getIteratorRef() const;
	//@}

protected:
	DCVIntervalSet m_intervals;
	DCVIntervalSet::iterator m_intervalItr;
};
typedef boost::shared_ptr<DynamicContinousScale> DynamicContinousScalePtr;

//------------------------------------------------------------------------------

class GST_API_EXPORT DynamicDiscreteScale
	: public DynamicColorScale
{
public:

	DynamicDiscreteScale();
	DynamicDiscreteScale(const DynamicDiscreteScale & other);
	DynamicDiscreteScale& operator=(const DynamicDiscreteScale& rhs);
	virtual DynamicColorScale * clone();

	virtual int size() const;
	virtual void clear();
	virtual DynamicColorScale::DynamicCSType getType() const;

	///@name DynamicColorValue getter/setter interface
	//@{
	virtual DynamicColorValuePtr GetColorValue(
		const TableAttributeVal & tval) const;
	virtual void insert(DynamicColorValuePtr dcv);
	virtual void drop(const DynamicColorValue & dcv);
	//@}

	///@name iteration interface
	//@{
	virtual void resetIterator();
	virtual bool incrIterator();
	virtual DynamicColorValuePtr getIteratorRef() const;
	//@}

protected:

	typedef boost::multi_index::multi_index_container <
		DCVQuantumPtr,
		boost::multi_index::indexed_by <
			//0-th index: ordered by DCVQuantum::getOrder()
			boost::multi_index::ordered_unique <
				boost::multi_index::const_mem_fun <
					DCVQuantum, int, &DCVQuantum::getOrder
				>
			>,
			//1-st index: hashed_unique by ordered by DCVQuantum::getValue()
			boost::multi_index::hashed_unique <
				boost::multi_index::const_mem_fun <
					DCVQuantum, std::string, &DCVQuantum::getValue
				>
			>
		>
	> DCVQuantumMultiContainer;

	static const int OrderIndex = 0;
	static const int ValueIndex = 1;
	typedef DCVQuantumMultiContainer::nth_index<0>::type OrderIndexType;
	typedef DCVQuantumMultiContainer::nth_index<1>::type ValueIndexType;

	DCVQuantumMultiContainer m_quantums;
	OrderIndexType::const_iterator m_quantumOrderItr;
};
typedef boost::shared_ptr<DynamicDiscreteScale> DynamicDiscreteScalePtr;

const DynamicColorScale::ID NEW_COLOSCALE_ID=-1;

} //namespace ClientUtils
} //namespace GST

#endif // _DynamicColorScaleStructs_h__
